﻿using System.Runtime.CompilerServices;

namespace zijian666.AnyExtensions;


/// <summary>
/// 忽略大小写和分隔符（下划线、连字符、空格、小数点）的字符串比较器。
/// </summary>
public class VariableNameComparer : IEqualityComparer<string?>
{
    private VariableNameComparer() { }
    /// <summary>
    /// 忽略大小写和分隔符（下划线、连字符、空格、小数点）的字符串比较器。
    /// </summary>
    public static readonly IEqualityComparer<string?> Instance = new VariableNameComparer();

    public bool Equals(string? x, string? y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x is null || y is null) return false;

        unsafe
        {
            fixed (char* px = x)
            fixed (char* py = y)
            {
                int i = 0, j = 0;
                int lenX = x.Length;
                int lenY = y.Length;

                while (true)
                {
                    // 如果都到末尾，说明相等
                    if (i >= lenX && j >= lenY) return true;
                    // 一个到末尾另一个没到，说明不相等
                    if (i >= lenX || j >= lenY) return false;

                    // 跳过非字母的分隔符
                    if (px[i].IsSeparator())
                    {
                        i++;
                        continue;
                    }
                    if (py[j].IsSeparator())
                    {
                        j++;
                        continue;
                    }

                    // 比较字母（忽略大小写）
                    if (!px[i].EqualsIgnoreCase(py[j]))
                        return false;

                    i++;
                    j++;
                }
            }
        }
    }

    public int GetHashCode(string? obj)
    {
        if (obj is null) return 0;

        int hash = 17;
        unsafe
        {
            unchecked
            {
                fixed (char* p = obj)
                {
                    for (int i = 0; i < obj.Length; i++)
                    {
                        char c = p[i];
                        if (c.IsSeparator()) continue;

                        // 转成小写字母（只处理 ASCII）
                        if (c >= 'A' && c <= 'Z')
                            c = (char)(c + 32);

                        hash = hash * 31 + c;
                    }
                }
            }
        }
        return hash;
    }

}
